home *** CD-ROM | disk | FTP | other *** search
/ Magnum One / Magnum One (Mid-American Digital) (Disc Manufacturing).iso / d13 / wayner.arc / WAYNER.TXT < prev   
Text File  |  1989-01-21  |  51KB  |  65 lines

  1. ================================
  2.  
  3.           APTCON
  4.  
  5. ================================
  6.  
  7.  
  8. UNIT APEcon;{APE 1.0 Copyright ⌐ 1988, Peter Wayner}{This is the code for version 1.0 of the APE compiler developed by Peter Wayner}{at Cornell University's Department of Computer Science. It is NOT in the public}{domain. It cannot be included as part of any other software without the }{written permission of the author.}{A version with windows, a much friendlier interface and a manual}{available for $45 from the author at 119 Ferris Place, Ithaca, NY 14850.}{A version for the IBM-PC is also available at the same price.}INTERFACE    USES        APEglobals, APEdata, APEutil;    PROCEDURE parsem;    {The nerve center for equation parsing.}IMPLEMENTATION    PROCEDURE push;    {Pushes new data onto the stack.}        VAR            old : stackpoint;        {The old stackpointer.}    BEGIN        old := stacktop;        new(stacktop);        stacktop^.up := old;        stacktop^.curleft := 0;        stacktop^.curright := 0;        stacktop^.curcon := 0;        stacktop^.state := 1    END;{push}    PROCEDURE pop;    {Pops the old data off the stack. }        VAR            old : stackpoint;    BEGIN        old := stacktop;        stacktop := stacktop^.up;        dispose(old)    END;{pop}    FUNCTION storephrase : integer;    {Takes the current phrase at the top of the stack and stores it away.}    {Returns a phraseid.}        VAR            p1 : phrase;        {The phrase to be stored away.}            symetric : integer;        {Set to 0  if it is a symetric connector 1 if left and 2 if right.}            duplicate : boolean;        {A boolean that is returned from addphrase true if the token exists before.}            tempid : integer;        {A temporary register to hold storephrase.}            dagnode : dagpoint;        {The potential new dagnode.}            reversed : boolean;        {Set to true if the program needs to rearrange the phrase.}    BEGIN        p1[2] := stacktop^.curcon;        CASE tokenmap[p1[2]]^.symetric OF            0 : {symetric}                IF stacktop^.curleft < stacktop^.curright THEN                    BEGIN                        p1[1] := stacktop^.curleft;                        p1[3] := stacktop^.curright;                        reversed := false                    END                ELSE                    BEGIN                        p1[1] := stacktop^.curright;                        p1[3] := stacktop^.curleft;                        reversed := true                    END;            1 : {left}                BEGIN                    p1[1] := stacktop^.curleft;                    p1[3] := stacktop^.curright;                    reversed := false                END;            2 : {The right branch must be explored first.}                BEGIN                    p1[3] := stacktop^.curleft;                    p1[1] := stacktop^.curright;                    reversed := true;                END        END;        symetric := tokenmap[p1[2]]^.symetric;        addphrase(p1, symetric, reversed, tempid, duplicate);    {Update the phrasemin array. This new connection obviously holds the }    {minimum of the two leaves.}        IF NOT duplicate THEN            BEGIN                new(dagnode);                dagnode^.phraseid := tempid;                dagnode^.visited := false; {Initialize the tree.}                dagnode^.top := true;{It must be the top, since it's never been here before.}                dagmap[tempid] := dagnode; {Put it in the table.}                dagnode^.left := dagmap[p1[1]];                dagnode^.left^.top := false;    {Because they're not the tops anymore.}                dagnode^.right := dagmap[p1[3]];                dagnode^.right^.top := false;        {This segment helps find the minimum phrase number for sorting and printing out}        {the tree in order.}                IF phrasemin[p1[1]] < phrasemin[p1[3]] THEN                    phrasemin[tempid] := phrasemin[p1[1]]                ELSE                    phrasemin[tempid] := phrasemin[p1[3]];            END;        storephrase := tempid;    END;{storephrase}    PROCEDURE parseline (VAR errorflag, sectionend : boolean);        {Takes a line of equations and parses it. Adds it to the data base}        {Using storephrase. Returns a false if an error occurs.}        VAR        {Receives tokenlist and tokencount globally. Also errorflag.}            curtoken : integer;            {A counter that points to the current token being parsed.}            synthtoken : integer;            {The latest synthesized token.}            wordlist : ARRAY[1..wordsperline] OF integer;            {A local list of the words in a line.}            tokenlist : ARRAY[1..tokensperline] OF integer;            {The results of condensing the wordlist into tokens.}            listcount : integer;            {An integer to count through the array wordlist.}            tokencount : integer;            {An integer to count through tokenlist. Points to last token in list.}            old : stackpoint;            {A variable for blowing the stack.}        {Other variables are held on the stack accessed with push and pop.}        {They are:                                                                               }        {curleft= the left hand token.                                            }        {curright=the right hand token.                                            }        {curcon=the current connector.                                         }        {state= 1 if completely empty.                                            }        {        =2  if just filled curleft.                                            }        {        =3  if just filled curcon.                                              }        {        =4  if just filled curright.                                             }        {        =5  if waiting to complete an equivalence assignment.            }        PROCEDURE grabline;    {grabs the next line and converts it into word uids.}            VAR    {Brings in the global array wordlist.}                w1 : word;            {The temporary word storage.}                endoline : boolean;            {A loop invariant that is false until an end to the line is found.}                placeholder : tablepoint;            {The pointer to the current id.}                i : integer;            {a counter.}                stopchar : char;            {a variable to hold the stopping character detected.}        BEGIN            listcount := 0;            endoline := false;            WHILE NOT endoline DO                BEGIN                    w1 := nextword(stopchar);                    IF w1[1] <> ' ' THEN                        IF checkword(w1, placeholder) THEN                            BEGIN                                listcount := listcount + 1;                                wordlist[listcount] := placeholder^.uid                            END                        ELSE                            BEGIN                                writeln(outputfile, 'Word left undefined:');                                scriptword(w1);                                errorflag := true                            END;                    CASE stopchar OF                        ';' :                             BEGIN                                listcount := listcount + 1;                                wordlist[listcount] := -1;                                endoline := true                            END;                        '(' :                             BEGIN                                listcount := listcount + 1;                                wordlist[listcount] := -2                            END;                        ')' :                             BEGIN                                listcount := listcount + 1;                                wordlist[listcount] := -3                            END;                        '.' :                             BEGIN                                listcount := listcount + 1;                                wordlist[listcount] := -4;                                endoline := true                            END;                        '=' :                             BEGIN                                listcount := listcount + 1;                                wordlist[listcount] := -5                            END;                        ' ', ':' :                             ;  {That's right, do nothing with a colon as well.}                    END;{case statement.}                    IF eof(inputfile) THEN                        endoline := true                END;{ The while loop.}        END;{grabline}        PROCEDURE condenseline;    {Takes a line and condenses it into tokens.}            VAR    {Takes wordlist as a global and returns tokenlist as a global.}    {listcount is a global set to the last word in the list.}    {tokencount is global set to the last token on the list.}                curword : integer;            {A pointer to the current word on wordlist.}                t1 : token;            {A data structure to search for tokens.}                tcount : integer;            {Place in the token list.}                tokenidea : boolean;            {True if the current token is an idea.}                placeholder : tokenpoint;            {This time a pointer to the place in the token list.}                i : integer;{*destroy me*}            LABEL                888;        BEGIN            curword := 1;            tokencount := 0;            tcount := 0;            tokenidea := true; {Assume we start in this condition.}            REPEAT                IF wordlist[curword] < 0 THEN                    BEGIN                        IF tcount > 0 THEN {A token exists. Store it.}                            BEGIN                                WHILE tcount < wordspertoken DO                                    BEGIN                                        tcount := tcount + 1; {Pad the token.}                                        t1[tcount] := 0                                    END;                                IF findtoken(t1, placeholder) THEN {Found!}                                    BEGIN                                        tokencount := tokencount + 1;                                        tokenlist[tokencount] := placeholder^.tokenid;                                        tcount := 0;                                    END                                ELSE                                    BEGIN                                        writeln(outputfile, 'This line contains an undefined token.');                                        errorflag := true;                                        curword := listcount + 1;{Blow us out of the loop.}                                        GOTO 888                                    END                {Now the token is found and stored away or an error is generated.}                {Take care of that punctuation.}                            END;                        tokencount := tokencount + 1;                        tokenlist[tokencount] := wordlist[curword];                    END                ELSE {It is a regular word.}                    BEGIN                        IF tokenidea = uidmap[wordlist[curword]]^.idea THEN                 {They agree. Save and continue.}                            BEGIN                                tcount := tcount + 1;                                t1[tcount] := wordlist[curword] {Add the new word.}                            END                        ELSE                            BEGIN  {They don't agree so some saving must be done.}                                IF tcount > 0 THEN                     {A token exists. Store it.}                                    BEGIN                                        WHILE tcount < wordspertoken DO                                            BEGIN                                                tcount := tcount + 1; {Pad the token.}                                                t1[tcount] := 0                                            END;                                        IF findtoken(t1, placeholder) THEN {Found!}                                            BEGIN                                                tokencount := tokencount + 1;                                                tokenlist[tokencount] := placeholder^.tokenid                                            END                                        ELSE                                            BEGIN                                                error('This line contains an undefined token.');                                                errorflag := true;                                                curword := listcount + 1;{Blow us out of the loop.}                                                GOTO 888                                            END                                    END;                {The old one is done. Save the new one.}                                tcount := 1;                                t1[1] := wordlist[curword];                                tokenidea := uidmap[t1[1]]^.idea;{ Is the current t1 an idea or what.}                            END                    END;                curword := curword + 1;{Keep going through the list.}888 :            UNTIL curword > listcount;        END;{condenseline}    {Now the real work of parse line.}    BEGIN        errorflag := false;{Start anew.}        grabline;{Get the next line of words.}        IF NOT errorflag THEN            condenseline; {Condense it into tokens. tokenlist and tokencount are set.}        stacktop := NIL;        push;{Begin with a clean stack. Sets the state to 1.}        curtoken := 1;        WHILE (curtoken <= tokencount) AND NOT errorflag DO            BEGIN                IF tokenlist[curtoken] < 0 THEN                    BEGIN                {Handle the punctuation.}                        CASE tokenlist[curtoken] OF                            -2 : {The Left parenthesis.}                                push; {This is easy!}                            -3 : {The right parenthesis.}                                BEGIN                                    IF (stacktop^.state = 4) THEN                                        synthtoken := storephrase {Store it away. Returns a token.}                                    ELSE IF stacktop^.state = 2 THEN                                        synthtoken := stacktop^.curleft                                    ELSE                                        BEGIN                                            error('Left and right parenthesis must contain a complete phrase.');                                            errorflag := true                                        END;                                    IF stacktop^.up = NIL THEN {Error!}                                        BEGIN                                            error('Mismatched parenthesis.');                                            errorflag := true                                        END                                    ELSE                                        pop;{It's been stored away. Now take this number and store it again.}                                    CASE stacktop^.state OF                                        1 :                                             BEGIN                                                stacktop^.curleft := synthtoken;                                                stacktop^.state := 2                                            END;                                        3 :                                             BEGIN                                                stacktop^.curright := synthtoken;                                                stacktop^.state := 4                                            END;                                        2, 4 :                                             BEGIN                                                error('A phrase (idea connector idea) forms a new idea.');                                                errorflag := true                                            END;                                        5 :                                             BEGIN {Start by pointing the current idea toward the top of the }                        {discovered phrase.}                                                dagmap[stacktop^.curleft] := dagmap[synthtoken];                                                phrasemap[synthtoken]^.equals := stacktop^.curleft; {Here, set up a pointer to the equas sign.}                                                pop;                                                stacktop^.state := 2;{Put us back to normal}                                                stacktop^.curleft := synthtoken {and so gently set us back where we are and make the equals transparent.}                                            END;                        {Here we need to fit the equals sign into the stack.}                        {What needs to be done:}                        {1. This location in the stack should be attached to the id.}                        {2. A back pointer must be established so printing can take }                        {    place.}                                    END;{case statement on stacktop^.state.}                                END;{-3, the right parenthesis.}                            -5 : {The equals sign.}                                BEGIN                                    IF stacktop^.state = 2 THEN {Everything is great.}                                        BEGIN                                            stacktop^.state := 5;{Go into equalsign waiting.}                                            push                                        END                                    ELSE                                        BEGIN                                            error('An equal s sign must be proceded by a single idea.');                                            errorflag := true                                        END                                END;{-5 the equals sign.}                            -1, -4 :{The end of the line. A semi-colon or a period.}                                BEGIN                                    IF stacktop^.up <> NIL THEN {Trouble. Parenthesis don't balance.}                                        IF stacktop^.up^.state = 5 THEN {finish off this equals sign.}                                            BEGIN {Start by pointing the current idea toward the top of the }                        {discovered phrase.}                                                dagmap[stacktop^.up^.curleft] := dagmap[synthtoken];                                            END                                        ELSE                                            BEGIN                                                error('Parenthesis do not balance.');                                                errorflag := true                                            END                    {curtoken must equal tokencount.}                                    ELSE IF (stacktop^.state = 4) THEN                                        synthtoken := storephrase{Store it away. Returns a token.}                                    ELSE IF stacktop^.state <> 2 THEN                                        BEGIN                                            error('Phrases must consist of idea-connector-idea.');                                            errorflag := true                                        END                                END;{of the semi-colon and period. -1 and -4}                        END{of the case statement.}                    END {of punctuation section.}                ELSE                    BEGIN                {The section that scores the tokens.}                        CASE stacktop^.state OF                            1 :  {Nothing parsed yet.}                                IF tokenmap[tokenlist[curtoken]]^.idea = true THEN {all is cool.}                                    BEGIN                                        stacktop^.curleft := tokenlist[curtoken];                                        stacktop^.state := 2                                    END                                ELSE                                    BEGIN                                        error('The first token of a phrase must be an idea.');                                        errorflag := true                                    END;                            2 : {Waiting for an idea.}                                IF tokenmap[tokenlist[curtoken]]^.idea <> true THEN {all is cool.}                                    BEGIN                                        stacktop^.curcon := tokenlist[curtoken];                                        stacktop^.state := 3                                    END                                ELSE                                    BEGIN                                        error('The second token of a phrase must be a connector.');                                        errorflag := true                                    END;                            3 :{All eyes on right.}                                IF tokenmap[tokenlist[curtoken]]^.idea = true THEN {all is cool.}                                    BEGIN                                        stacktop^.curright := tokenlist[curtoken];                                        stacktop^.state := 4                                    END                                ELSE                                    BEGIN                                        error('The third token of a phrase must be an idea.');                                        errorflag := true                                    END;                            4 :{Could be trouble.}                                IF tokenmap[tokenlist[curtoken]]^.idea <> true THEN {all is cool.}                                    BEGIN                    {idea-connector-idea-connector. Implied parenthesis.}                                        stacktop^.curleft := storephrase;                                        stacktop^.curcon := tokenlist[curtoken];                                        stacktop^.state := 3                                    END                                ELSE                                    BEGIN                                        error('The ideas and the connectors must alternate.');                                        errorflag := true                                    END;                            5 :                                 ;{Shouldn't be here.}                        END;{ of the case statement}                    END;{of the if statement.}                curtoken := curtoken + 1;            END;{of invarient curtoken<=tokencount. Everything must be processed.}{Blow out the stack. Clean up.}        WHILE stacktop <> NIL DO            BEGIN                old := stacktop;                stacktop := stacktop^.up;                dispose(old)            END;        IF wordlist[listcount] = -4 THEN {Period, end of secton.}            sectionend := true    END;{parseline}    PROCEDURE parsem;    {The nerve center for equation parsing.}        VAR            sectionend : boolean;        {To be passed back and forth to signal the end.}            errorflag : boolean;        {The local error flag to be passed back and forth .}    BEGIN        sectionend := false;        errorflag := false;        REPEAT            BEGIN                parseline(errorflag, sectionend);                IF errorflag THEN                    BEGIN                        mastererror := true;                        errorflag := false                    END            END        UNTIL sectionend OR eof(inputfile);    END;{parsem.}END.{box4con2}
  9.  
  10.  
  11.  
  12.  
  13. ================================
  14.  
  15.           APTDATA
  16.  
  17. ================================
  18.  
  19.  
  20. UNIT APEdata;{APE 1.0 Copyright ⌐ 1988, Peter Wayner}{This is the code for version 1.0 of the APE compiler developed by Peter Wayner}{at Cornell University's Department of Computer Science. It is NOT in the public}{domain. It cannot be included as part of any other software without the }{written permission of the author.}{A version with windows, a much friendlier interface and a manual}{available for $45 from the author at 119 Ferris Place, Ithaca, NY 14850.}{A version for the IBM-PC is also available at the same price.}{This contains the central routines for data access of the symbol}{table and the stack.}INTERFACE    USES        APEglobals, APEutil;    FUNCTION checkword (VAR name : word;                                    VAR placeholder : tablepoint) : boolean;    PROCEDURE addword (VAR name : word;                                    idea : boolean;                                    VAR uid : integer);    FUNCTION findtoken (VAR t1 : token;                                    VAR placeholder : tokenpoint) : boolean;    PROCEDURE addtoken (VAR t1 : token;                                    idea : boolean;                                    symetric : integer;                                    connection : boolean;                                    VAR tokenid : integer;                                    VAR duplicate : boolean);    FUNCTION findphrase (VAR p1 : phrase;                                    VAR placeholder : phrasepoint) : boolean;    PROCEDURE addphrase (VAR p1 : phrase;                                    symetric : integer;                                    reversed : boolean;                                    VAR phraseid : integer;                                    VAR duplicate : boolean);IMPLEMENTATION    FUNCTION hash (name : word) : integer;    {This function takes a word and hashes it to return a number}    {From 0 to hashsize.}    BEGIN        hash := (ord(name[1]) + ord(name[2]) + ord(name[3])) MOD hashsize + 1    END;    FUNCTION checkword; {(var name : word;}                    {var placeholder : tablepoint) : boolean;}    {This procedure takes a word and finds it in the symbol table. }    {It returns true if word is found as well as a pointer to the place}    {in the table the word is kept. If it returns false, placeholder }    {contains the last place where the search terminated.}        VAR            hashed : integer;        {The result of the hash.}            notbottom : boolean;        {A boolean variable to signal the bottom of a table.}    BEGIN        hashed := hash(name); {Find a binary tree to begin searching.}        IF hashmap[hashed] = NIL THEN            BEGIN                checkword := false;{Obviously not found.}                placeholder := NIL; {Return nothing.}            END        ELSE        {The location already holds a value. Continue on.}            BEGIN                placeholder := hashmap[hashed];{Load the value for the invarient.}                notbottom := true;{Can't be there yet.}                WHILE (name <> placeholder^.name) AND notbottom DO                    BEGIN                        IF name < placeholder^.name THEN                            IF placeholder^.left = NIL THEN                                notbottom := false {The left bottom has been reached.}                            ELSE                                placeholder := placeholder^.left                {Or consider the right hand side.}                        ELSE IF placeholder^.right = NIL THEN                            notbottom := false {The right bottom is reached.}                        ELSE                            placeholder := placeholder^.right;                    END;{While loop.}        {An end is found.}                checkword := notbottom;            END;{Else statement begin.}    END;{checkword}    PROCEDURE addword; {(var name : word;}                    {idea : boolean;}                    {var uid : integer);}    {This function returns the uid. idea and symetric are two traits to be stored}    {along side the word.}        VAR            placeholder : tablepoint;        {The pointer to the place of insertion.}            oldplace : tablepoint;        {The last placeholder.}            hashed : integer;        {The integer for the hash array.}    BEGIN        IF checkword(name, placeholder) THEN {checkword returns a location in placeholder.}        {If this is true then trouble! Signal error.}            BEGIN                IF (NOT idea) AND placeholder^.idea THEN                    BEGIN                        error('Words in a Connector cannot duplicate an Idea. ');                        uid := 0; {Return a zero to signify trouble.}                    END                ELSE                    uid := placeholder^.uid;            END        ELSE            BEGIN                oldplace := placeholder;{Save the old record.}                new(placeholder);                IF oldplace = NIL THEN        {Then this section of the hash table hasn't been used.}                    BEGIN                        hashed := hash(name);                        hashmap[hashed] := placeholder                    END                ELSE IF name < oldplace^.name THEN {Then we're already deep in the table.}                    oldplace^.left := placeholder                ELSE                    oldplace^.right := placeholder;                placeholder^.name := name;                placeholder^.idea := idea;                placeholder^.left := NIL;                placeholder^.right := NIL;                IF lastuid < maxuid THEN                    BEGIN                        lastuid := lastuid + 1;                        placeholder^.uid := lastuid;                        uid := lastuid {Return this value.}                    END                ELSE                    BEGIN                        error('Too many ideas.');{Signal an overflow }                        stop                    END;                uidmap[lastuid] := placeholder{Fill in the second table.}            END    END;{addword}{Now add the tokens.}    FUNCTION findtoken;{(var t1 : token;}                {var placeholder : tokenpoint) : boolean;}    {This procedure takes a token and finds it in the symbol table. }    {It returns true if token is found as well as a pointer to the place}    {in the table the token is kept. If it returns false, placeholder }    {contains the last place where the search terminated.}        VAR            notbottom : boolean;        {A boolean variable to signal the bottom of a table.}    BEGIN    {Binary tree searching begins at tokentop}        IF tokentop = NIL THEN            BEGIN                findtoken := false;{Obviously not found.}                placeholder := NIL; {Return nothing.}            END        ELSE        {The location already holds a value. Continue on.}            BEGIN                placeholder := tokentop;{Load the value for the invarient.}                notbottom := true;{Can't be there yet.}                WHILE (NOT equaltoken(t1, placeholder^.t1)) AND notbottom DO                    BEGIN                        IF lesstoken(t1, placeholder^.t1) THEN                            IF placeholder^.left = NIL THEN                                notbottom := false {The left bottom has been reached.}                            ELSE                                placeholder := placeholder^.left                {Or consider the right hand side.}                        ELSE IF placeholder^.right = NIL THEN                            notbottom := false {The right bottom is reached.}                        ELSE                            placeholder := placeholder^.right;                    END;{While loop.}        {An end is found.}                findtoken := notbottom;            END;{Else statement begin.}    END;{findtoken}    PROCEDURE addtoken;{(var t1 : token;}                {idea:boolean; symetric:integer;connection : boolean;}                {var tokenid:integer;}                {var duplicate:boolean);}    {This function returns the tokenid in tokenid if t1 is added to the symbol table successfully}    {and zero if a match is found. idea and symetric are two traits to be stored}    {along side the token. }        VAR            placeholder : tokenpoint;        {The pointer to the place of insertion.}            oldplace : tokenpoint;        {The last placeholder.}            dagnode : dagpoint;        {The pointer to the nodes of the directed acyclic graph holding the final form.}    BEGIN        IF findtoken(t1, placeholder) THEN {findtoken returns a location in placeholder.}            BEGIN                duplicate := true;                tokenid := placeholder^.tokenid            END        ELSE            BEGIN                oldplace := placeholder;{Save the old record.}                new(placeholder);                IF oldplace = NIL THEN        {Then tabletop hasn't been used.}                    tokentop := placeholder                ELSE IF lesstoken(t1, oldplace^.t1) THEN {Then we're already deep in the table.}                    oldplace^.left := placeholder                ELSE                    oldplace^.right := placeholder;                placeholder^.t1 := t1;                placeholder^.idea := idea;                placeholder^.symetric := symetric;                placeholder^.connection := connection;                placeholder^.left := NIL;                placeholder^.right := NIL;                IF lasttokenid < maxtokenid THEN                    BEGIN                        lasttokenid := lasttokenid + 1;                        lastphraseid := lastphraseid + 1;                        phrasemap[lastphraseid] := NIL;{Tell the map that this is blank.}                        phrasemin[lastphraseid] := lastphraseid;        {Now add a leaf in the DAG for later printouts....}        {These things are known as phrases.}                        new(dagnode);                        dagnode^.phraseid := lastphraseid;                        dagnode^.left := NIL;                        dagnode^.right := NIL;                        dagnode^.visited := false;                        dagnode^.top := false;{A leaf can never be the tops. Only composites.}                        dagmap[lastphraseid] := dagnode;                        placeholder^.tokenid := lasttokenid                    END                ELSE                    BEGIN                        error('Too many ideas.');{Signal an overflow }                        stop                    END;                tokenmap[lasttokenid] := placeholder;                duplicate := false;                tokenid := lasttokenid {save it for posterity.}            END    END;{addtoken}    FUNCTION findphrase;{(var p1 : phrase;}                {var placeholder : phrasepoint) : boolean;}    {This procedure takes a phrase and finds it in the symbol table. }    {It returns true if phrase is found as well as a pointer to the place}    {in the table the phrase is kept. If it returns false, placeholder }    {contains the last place where the search terminated.}        VAR            notbottom : boolean;        {A boolean variable to signal the bottom of a table.}    BEGIN    {Binary tree searching begins at phrasetop}        IF phrasetop = NIL THEN            BEGIN                findphrase := false;{Obviously not found.}                placeholder := NIL; {Return nothing.}            END        ELSE        {The location already holds a value. Continue on.}            BEGIN                placeholder := phrasetop;{Load the value for the invarient.}                notbottom := true;{Can't be there yet.}                WHILE (NOT equalphrase(p1, placeholder^.p1)) AND notbottom DO                    BEGIN                        IF lessphrase(p1, placeholder^.p1) THEN                            IF placeholder^.left = NIL THEN                                notbottom := false {The left bottom has been reached.}                            ELSE                                placeholder := placeholder^.left                {Or consider the right hand side.}                        ELSE IF placeholder^.right = NIL THEN                            notbottom := false {The right bottom is reached.}                        ELSE                            placeholder := placeholder^.right;                    END;{While loop.}        {An end is found.}                findphrase := notbottom;            END;{Else statement begin.}    END;{findphrase}    PROCEDURE addphrase;{(var p1 : phrase;}                { symetric: integer;reversed:boolean;}                {var phraseid:integer;}                {var duplicate:boolean);}    {This function returns the phraseid in phraseid if p1 is added to the symbol table successfully}    {and zero if a match is found. idea and symetric are two traits to be stored}    {along side the phrase. }        VAR            placeholder : phrasepoint;        {The pointer to the place of insertion.}            oldplace : phrasepoint;        {The last placeholder.}    BEGIN        IF findphrase(p1, placeholder) THEN {findphrase returns a location in placeholder.}            BEGIN                duplicate := true;                phraseid := placeholder^.phraseid            END        ELSE            BEGIN                oldplace := placeholder;{Save the old record.}                new(placeholder);                IF oldplace = NIL THEN        {Then tabletop hasn't been used.}                    phrasetop := placeholder                ELSE IF lessphrase(p1, oldplace^.p1) THEN {Then we're already deep in the table.}                    oldplace^.left := placeholder                ELSE                    oldplace^.right := placeholder;                placeholder^.p1 := p1;                placeholder^.symetric := symetric;                placeholder^.reversed := reversed;                placeholder^.equals := 0;{It doesn't equal anything if nothing's been done.}                placeholder^.left := NIL;                placeholder^.right := NIL;                IF lastphraseid < maxphraseid THEN                    BEGIN                        lastphraseid := lastphraseid + 1;                        lasttokenid := lasttokenid + 1;{Update here as well to make sure the}                {parser works correctly. It assumes the token number=phrasenumber}                        tokenmap[lasttokenid] := NIL;                        placeholder^.phraseid := lastphraseid                    END                ELSE                    BEGIN                        error('Too many ideas.');{Signal an overflow }                        stop                    END;                phrasemap[lastphraseid] := placeholder;                duplicate := false;                phraseid := lastphraseid {save it for posterity.}            END    END;{addphrase}END.
  21.  
  22.  
  23.  
  24. ================================
  25.  
  26.           APTGLOBA.LS
  27.  
  28. ================================
  29.  
  30.  
  31. UNIT APEglobals;{APE 1.0 Copyright ⌐ 1988, Peter Wayner}{This is the code for version 1.0 of the APE compiler developed by Peter Wayner}{at Cornell University's Department of Computer Science. It is NOT in the public}{domain. It cannot be included as part of any other software without the }{written permission of the author.}{A version with windows, a much friendlier interface and a manual}{available for $45 from the author at 119 Ferris Place, Ithaca, NY 14850.}{A version for the IBM-PC is also available at the same price.}INTERFACE{    Global constants.        }    CONST        linesize = 90;        {The maximum length of a line of text.}        wordsize = 14;        {The maximum size of a word.}        maxuid = 1024;        {The maximum number of universal identifiers.}        hashsize = 10;        {The hash table runs from 0 to hashsize.}        wordspertoken = 5;        {The maximum number of words per token.}        maxtokenid = 1024;        {The maximum number of tokens.}        wordsperline = 150;        {number of words per line in an equation (connection).}        tokensperline = 100;        {Maximum number of tokens in an equation line.}        maxphraseid = 1024;        {The maximum number of phrases allowed.}        {Must be equal to maxtokenid!!!! They are one in the same.}    TYPE        word = PACKED ARRAY[1..wordsize] OF char;        {A word is a kludged bit of work to deal with PASCAL's lexical intransagence.}        {A word is effectively the length of an id.}{This structure is used to store the symbol table.}        tablepoint = ^symbol;        symbol = RECORD                uid : integer; {A unique id for each word.}                name : word; {The name stored here.}                idea : boolean;{A truth value for idea=true, connector=false}                left, right : tablepoint;{Pointers to the left and right branches.}            {The left points to words <name and right points to those > name.}            END;        pointarray = ARRAY[1..maxuid] OF tablepoint;        {The array that will contain the uid-> symbol map.}        hasharray = ARRAY[0..hashsize] OF tablepoint;        {Use the function hash and then use hash array to find the first symbol.}{This structure is used to store the token table. Tokens consist of arrays}{of uids. }        token = ARRAY[1..wordspertoken] OF integer;        tokenpoint = ^tokenrecord;        tokenrecord = RECORD                tokenid : integer; {A unique id for each word.}                t1 : token; {The name stored here.}                idea : boolean;{A truth value for idea=true, connector=false}                symetric : integer;{0=symmetric,1=left first,2=right first}                connection : boolean;{A synthesized word.}                left, right : tokenpoint;{Pointers to the left and right branches.}            {The left points to words <name and right points to those > name.}            END;        tokenarray = ARRAY[1..maxtokenid] OF tokenpoint;        {This array will contain the map of tokenid -> tokenrecord}{This is a stack used by the parser.}        stackpoint = ^stackrecord;        stackrecord = RECORD                curleft : integer;{The uid of the left token}                curcon : integer;{The uid of the connector}                curright : integer;{The uid of the right token}                up : stackpoint;{The way up.}                state : 1..5;{The current state of the parser.}            END;{This is the data types for storing phrases.}        phrase = ARRAY[1..3] OF integer;        {An idea-connector-idea triplet.}        phrasepoint = ^phraserecord;        phraserecord = RECORD                phraseid : integer; {A unique id for each word.}                p1 : phrase; {The name stored here.}                symetric : integer;{0=symmetric,1=left first,2=right first}                reversed : boolean;{This is true if the program has reversed the order of the phrase.}                equals : integer;{This is a pointer to another tokenid if an equals sign assigns it to this phrase.}                left, right : phrasepoint;{Pointers to the left and right branches.}            {The left points to words <name and right points to those > name.}            END;        phrasearray = ARRAY[1..maxphraseid] OF phrasepoint;        {This array will contain the map of phraseid -> phraserecord}        phrasedata = ARRAY[1..maxphraseid] OF integer;        {This will contain data about the phrases.}{This section contains the data type for the directed acyclic graph }{that summarizes the structure of the essay.}        dagpoint = ^dagrecord;        dagrecord = RECORD                phraseid : integer;            {The phrase id of this node. Duplicates an entry in the phrasetree.}                left, right : dagpoint;            {Pointers to the children.}                visited : boolean;            {Used in depth-first search.}                top : boolean;            {This is true if there is nothing with a node that points down to it.}            END;        dagarray = ARRAY[1..maxphraseid] OF dagpoint;        {Holds the map between phraseid and node in the dag.}    VAR        lastuid : integer;        {Last uid assigned. Should never exceed maxuid.}        uidmap : pointarray;        {The array that contains the uid-> symbol map.}        hashmap : hasharray;        {The array that contains the hash table.}        tokenmap : tokenarray;        {Contains the tokenid -> tokenrecord table.}        lasttokenid : integer;        {Last tokenid assigned.}        tokentop : tokenpoint;        {Pointer to the top of the token stack.}        stacktop : stackpoint;        {The top of the stack.}        phrasetop : phrasepoint;        {Pointer to the top of the phrase tree.}        phrasemap : phrasearray;        {Contains the phraseid -> phraserecord table.}        phrasemin : phrasedata;        {Contains the smallest tokenid held in the tree below a value.}        lastphraseid : integer;        {Last phraseid assigned.}        dagmap : dagarray;        {Contains a map from phraseid to dat.}        ideanum, connum, equnum : integer;        {Integers to hold the numbers of the global tokens }        {IDEAS,CONNECTORS,CONNECTIONS respectively.}        leftnum, rightnum, symnum : integer;{Integers to hold the numbers of the global tokens }        {LEFT,RIGHT,SYMETRIC respectively.}        mastererror : boolean;        {This flag is set to stop complilation.}        inputfile, outputfile : text;        inputname, outputname : Str255;IMPLEMENTATIONEND.
  32.  
  33.  
  34.  
  35. ================================
  36.  
  37.           APTUTIL
  38.  
  39. ================================
  40.  
  41.  
  42. UNIT APEutil;{APE 1.0 Copyright ⌐ 1988, Peter Wayner}{This is the code for version 1.0 of the APE compiler developed by Peter Wayner}{at Cornell University's Department of Computer Science. It is NOT in the public}{domain. It cannot be included as part of any other software without the }{written permission of the author.}{A version with windows, a much friendlier interface and a manual}{available for $45 from the author at 119 Ferris Place, Ithaca, NY 14850.}{A version for the IBM-PC is also available at the same price.}INTERFACE    USES        APEglobals;    PROCEDURE error (cause : STRING);    PROCEDURE warning (cause : STRING);    PROCEDURE stop;    FUNCTION wordify (st : STRING) : word;    FUNCTION equaltoken (VAR t1, t2 : token) : boolean;    {Returns true if t1=t2.}    FUNCTION lesstoken (VAR t1, t2 : token) : boolean;    {Returns true if t1<t2.}    FUNCTION equalphrase (VAR p1, p2 : phrase) : boolean;    {Returns true if p1=p2.}    FUNCTION lessphrase (VAR p1, p2 : phrase) : boolean;    {Returns true if p1<p2.}    PROCEDURE scriptword (VAR w1 : word);    {Writes out a line.}    PROCEDURE scripttoken (VAR t1 : token);    {Writes out a token.}    FUNCTION nextword (VAR stopchar : char) : word;    PROCEDURE skiptoend (VAR stopchar : char);    {Skips over everything until it hits a stop character.}IMPLEMENTATION    PROCEDURE error; {(cause : string)}    {If an error is found. Print it out!}    BEGIN        writeln(outputfile, cause)    END;{error}    PROCEDURE warning;{(cause : string)}    {Just a warning, son.}    BEGIN        writeln(outputfile, cause)    END;{warning}    PROCEDURE stop;    {Signal a real bad problem. Include close file statements.}    BEGIN    END;{Stop}    FUNCTION wordify;{( st :string): word }    {Changes a string to standard pascal word.}        VAR            i : integer;            w1 : word;         {A temporary buffer.}    BEGIN        FOR i := 1 TO wordsize DO            w1[i] := ' ';        FOR i := 1 TO length(st) DO            w1[i] := st[i];        wordify := w1;{Set the value to return.}    END;{wordify}    FUNCTION equaltoken; {(var t1, t2 : token) : boolean;}    {Returns true if t1=t2.}        VAR            i : integer;    BEGIN        i := 1;        WHILE (t1[i] = t2[i]) AND (i < wordspertoken) DO            i := i + 1;        equaltoken := (i = wordspertoken) AND (t1[i] = t2[i]);    END;{equaltoken}    FUNCTION lesstoken;{(var t1, t2 : token) : boolean;}    {Returns true if t1<t2.}        VAR            i : integer;    BEGIN        i := 1;        WHILE (t1[i] = t2[i]) AND (i < wordspertoken) DO            i := i + 1;        lesstoken := (t1[i] < t2[i]);    END;{lesstoken}    FUNCTION equalphrase; {(var p1, p2 : phrase) : boolean;}    {Returns true if p1=p2.}    BEGIN        IF p1[1] = p2[1] THEN            BEGIN                IF p1[2] = p2[2] THEN                    BEGIN                        IF p1[3] = p2[3] THEN                            equalphrase := true                        ELSE                            equalphrase := false                    END                ELSE                    equalphrase := false            END        ELSE            equalphrase := false    END;{equalphrase}    FUNCTION lessphrase;{(var p1, p2 : phrase) : boolean;}    {Returns true if p1<p2.}        VAR            i : integer;    BEGIN        i := 1;        WHILE (p1[i] = p2[i]) AND (i < 3) DO            i := i + 1;        lessphrase := (p1[i] < p2[i]);    END;{lessphrase}    PROCEDURE scriptword;{(var w1 : word);}    {Writes out a line.}        VAR            i : integer;    BEGIN        FOR i := 1 TO wordsize DO            write(outputfile, w1[i]);        write(outputfile, ' ');    END;{scriptword}    PROCEDURE scripttoken; { (var t1 : token);}    {Writes out a token.}        VAR            i : integer;    BEGIN        FOR i := 1 TO wordspertoken DO            write(outputfile, t1[i]);        writeln(outputfile);    END;{scripttoken}    PROCEDURE skiptoend;{(var stopchar : char);}    {Skips over everything until it hits a stop character.}        VAR            a : char;        {something to get us through the file.}    BEGIN        read(inputfile, stopchar);        IF stopchar = '{' THEN            WHILE (stopchar <> '}') AND NOT eof(inputfile) DO                read(inputfile, stopchar);{Scan to the end of the comment.}        IF a = '}' THEN            read(inputfile, stopchar);        IF eof(inputfile) THEN            BEGIN                error('Premature end of file.');                stop {Take care of those nasty error messages.}            END;        WHILE (stopchar <> '.') AND (stopchar <> ';') AND (stopchar <> ':') DO            BEGIN                read(inputfile, stopchar);                IF stopchar = '{' THEN                    WHILE (stopchar <> '}') AND NOT eof(inputfile) DO                        read(inputfile, stopchar);{Scan to the end of the comment.}                IF a = '}' THEN                    read(inputfile, stopchar);                IF eof(inputfile) THEN                    BEGIN                        error('Premature end of file.');                        stop {Take care of those nasty error messages.}                    END            END    END; {Skiptoend}    FUNCTION nextword; {(var stopchar : char) : word;}        VAR            loopcool : boolean;        {Keeps track of the loop.}            w1 : word;        {Temporary word storage.}            i : integer;        {The usual role of drudgework. Stop lexicism. Free i's from counting.}            a : char;        {something to get us through the file.}    BEGIN        loopcool := true;{Set the boolean.}        i := 1;{And the counter of the word.}        read(inputfile, a);        IF a = '{' THEN            WHILE (a <> '}') AND NOT eof(inputfile) DO                read(inputfile, a);{Scan to the end of the comment.}        IF a = '}' THEN            read(inputfile, a);        IF eof(inputfile) THEN            loopcool := false;{Pull off any leading spaces.}        WHILE (a = ' ') AND NOT eof(inputfile) DO            BEGIN                read(inputfile, a);                IF a = '{' THEN                    WHILE (a <> '}') AND NOT eof(inputfile) DO                        read(inputfile, a);{Scan to the end of the comment.}                IF a = '}' THEN                    read(inputfile, a);            END;        IF a = ' ' THEN            loopcool := false        ELSE IF a = '(' THEN            loopcool := false        ELSE IF a = ')' THEN            loopcool := false        ELSE IF a = '=' THEN            loopcool := false        ELSE IF a = ':' THEN            loopcool := false        ELSE IF a = ';' THEN            loopcool := false        ELSE IF a = '.' THEN            loopcool := false;        WHILE loopcool DO            BEGIN                IF i <= wordsize THEN                    BEGIN                        w1[i] := a;                        i := i + 1                    END;                read(inputfile, a);                IF a = '{' THEN                    WHILE (a <> '}') AND NOT eof(inputfile) DO                        read(inputfile, a);{Scan to the end of the comment.}                IF a = '}' THEN                    read(inputfile, a);                IF eof(inputfile) THEN                    loopcool := false;{Blow out of here.}                IF a = ' ' THEN                    loopcool := false                ELSE IF a = '(' THEN                    loopcool := false                ELSE IF a = ')' THEN                    loopcool := false                ELSE IF a = '=' THEN                    loopcool := false                ELSE IF a = ':' THEN                    loopcool := false                ELSE IF a = ';' THEN                    loopcool := false                ELSE IF a = '.' THEN                    loopcool := false            END;{Pad with spaces.}        WHILE i <= wordsize DO            BEGIN                w1[i] := ' ';                i := i + 1            END;        stopchar := a;{Save the offending character.}        nextword := w1    END;{nextword}END.
  43.  
  44.  
  45. ================================
  46.  
  47.           APTPRINT
  48.  
  49. ================================
  50.  
  51.  
  52. UNIT APEprint;{APE 1.0 Copyright ⌐ 1988, Peter Wayner}{This is the code for version 1.0 of the APE compiler developed by Peter Wayner}{at Cornell University's Department of Computer Science. It is NOT in the public}{domain. It cannot be included as part of any other software without the }{written permission of the author.}{A version with windows, a much friendlier interface and a manual}{available for $45 from the author at 119 Ferris Place, Ithaca, NY 14850.}{A version for the IBM-PC is also available at the same price.}    {Contains the printout routines.}INTERFACE    USES        APEglobals;    PROCEDURE print;    {Prints 'em out.}IMPLEMENTATION    PROCEDURE scriptword (VAR w1 : word);    {Writes out a line.}        VAR            i, j : integer;    BEGIN        j := wordsize;        WHILE (w1[j] = ' ') AND (j > 0) DO            j := j - 1;        FOR i := 1 TO j DO            write(outputfile, w1[i]);        write(outputfile, ' ');    END;{scriptword}    PROCEDURE pphrase (phrasenum : integer);    {Takes a phrase and prints it out neatly. Will handle recursion.}        VAR            p1 : phrase;        {The local phrase variable.}            i : integer;            t2 : token;        {The token of the connector.}            placeholder : phrasepoint;        {A time saver. No need to access the array twice.}        PROCEDURE pside (side : integer);    {prints left or right depending upon whether side:=1 or 3.}            VAR                i, j : integer;                t1 : token;                place2 : phrasepoint;            {Another time saver.}        BEGIN            place2 := phrasemap[p1[side]];            IF place2 <> NIL THEN                IF place2^.equals > 0 THEN                    BEGIN            {We've been here before. Use the substitute token.}                        t1 := tokenmap[place2^.equals]^.t1;{get the token.}                        i := 1;                        WHILE (t1[i] <> 0) AND (i <= wordspertoken) DO                            BEGIN                                scriptword(uidmap[t1[i]]^.name);                                i := i + 1                            END;                    END                ELSE                    BEGIN                        write(outputfile, '(');                        pphrase(p1[side]);                        write(outputfile, ')');                    END            ELSE {It's not a connection, so it's a tokenid too!}                BEGIN                    t1 := tokenmap[p1[side]]^.t1;{get the token.}                    i := 1;                    WHILE (t1[i] <> 0) AND (i <= wordspertoken) DO                        BEGIN                            scriptword(uidmap[t1[i]]^.name);                            i := i + 1                        END;                END        END;{pside}    BEGIN {pphrase}        placeholder := phrasemap[phrasenum];        IF placeholder^.equals > 0 THEN            BEGIN        {Well here we are at an equality. Write it out so the reader knows where he is.}                t2 := tokenmap[placeholder^.equals]^.t1;                i := 1;                WHILE (t2[i] <> 0) AND (i <= wordspertoken) DO                    BEGIN                        scriptword(uidmap[t2[i]]^.name);                        i := i + 1                    END;                write(outputfile, '=')            END;        p1 := placeholder^.p1;        t2 := tokenmap[p1[2]]^.t1;        i := 1;        IF placeholder^.reversed THEN            BEGIN                pside(3);                WHILE (t2[i] <> 0) AND (i <= wordspertoken) DO                    BEGIN                        scriptword(uidmap[t2[i]]^.name);                        i := i + 1                    END;                pside(1)            END        ELSE            BEGIN                pside(1);                WHILE (t2[i] <> 0) AND (i <= wordspertoken) DO                    BEGIN                        scriptword(uidmap[t2[i]]^.name);                        i := i + 1                    END;                pside(3)            END    END;{pphrase}    PROCEDURE depth (node : dagpoint);    {Recursive decent printer. Prints in-order traversal of the dag.}        VAR            t1 : token;        {Contains the token to be printed.}            p1 : phrase;        {A temporary phrase to get results for t1}            i : integer;        {A counter.}    BEGIN        IF NOT node^.visited THEN            BEGIN                IF node^.left = NIL THEN {At a leaf. Either both nil or neither nil.}                    BEGIN                        t1 := tokenmap[node^.phraseid]^.t1;                        write(outputfile, 'Describe :');                        i := 1;                        WHILE (t1[i] <> 0) AND (i <= wordspertoken) DO                            BEGIN                                scriptword(uidmap[t1[i]]^.name);                                i := i + 1                            END;                        writeln(outputfile);                    END                ELSE                    BEGIN                        depth(node^.left);                        depth(node^.right);                        write(outputfile, 'Show how:');                        pphrase(node^.phraseid);                        writeln(outputfile)                    END;                node^.visited := true;            END    END;{depth}    PROCEDURE print;    {The main printing machine.}        VAR            finished : boolean;        {The old end of loop condition.}            minimum : integer;        {Contains the minimum minimum id found so far.}            dome : integer;        {This contains the next integer to be done. do me.}            i : integer;        {A simple counter.}    BEGIN        writeln(outputfile, 'The Outline:');        writeln(outputfile);        REPEAT            finished := true;            minimum := lastphraseid;{The largest minimum is lasttokenid. This is definitely >}            dome := 0;{This one holds the minimum id found.}            FOR i := lastphraseid DOWNTO 1 DO        {Scan the list for the minimum id. This is the tree to search next.}                IF NOT dagmap[i]^.visited AND dagmap[i]^.top THEN {This one needs to be done.}                    BEGIN                        finished := false;                        IF phrasemin[i] <= minimum THEN {Equals because we want the first node with the min.}                            BEGIN                                minimum := phrasemin[i];                                dome := i                            END                    END;            IF dome > 0 THEN                depth(dagmap[dome]);        UNTIL finished;    END;END.{box4print}
  53.  
  54.  
  55. ================================
  56.  
  57.           APTTOP
  58.  
  59. ================================
  60.  
  61.  
  62. PROGRAM apetop;{APE 1.0 Copyright ⌐ 1988, Peter Wayner}{This is the code for version 1.0 of the APE compiler developed by Peter Wayner}{at Cornell University's Department of Computer Science. It is NOT in the public}{domain. It cannot be included as part of any other software without the }{written permission of the author.}{A version with windows, a much friendlier interface and a manual}{available for $45 from the author at 119 Ferris Place, Ithaca, NY 14850.}{A version for the IBM-PC is also available at the same price.}    USES        APEglobals, APEutil, APEdata, APEprint, APEcon;    PROCEDURE initialize;    {Gets everything rolling.}        VAR            i : integer;            idea : boolean;        {A dummy variable to keep addword working.}            w1 : word;        {Something to hold the words.}    BEGIN        lastuid := 0;        lasttokenid := 0;        lastphraseid := 0;        tokentop := NIL; {Set the top of the token stack.}        FOR i := 0 TO hashsize DO            hashmap[i] := NIL;        stacktop := NIL;        phrasetop := NIL;    {Now store away all the words.}        idea := true;        w1 := wordify('IDEAS');        addword(w1, idea, ideanum);        w1 := wordify('CONNECTORS');        addword(w1, idea, connum);        w1 := wordify('CONNECTIONS');        addword(w1, idea, equnum);{Equations are often a synnonym for connections}        w1 := wordify('LEFT');        addword(w1, idea, leftnum);        w1 := wordify('RIGHT');        addword(w1, idea, rightnum);        w1 := wordify('SYMETRIC');        addword(w1, idea, symnum);    END;    PROCEDURE scanline (idea : boolean);    {Scans a line of connections storing words or ideas until all are stored.}    {If idea is true than a line of ideas is being scanned, otherwise a line of }    {connectors are being searched.}        VAR            stopchar : char;        {The character that stops the nextword subroutine.}            w1 : word;        {A word that is being operated upon.}            wordnum : integer;        {The number of the word that it is turned into.}            t1 : token;        {The current token being stored.}            tokencount : integer;        {A placeholder in the current token.}            symetric : integer;        {0=symetric,1=left first,2=right first connector.}            placeholder : tablepoint;        {Holds the position in the word table when checkword is used.}            connection : boolean;        {A spurious variable to allow the addtoken procedure to work.}            tokenid : integer;        {Another one.}            duplicate : boolean;        {Not so spurious. If it is a duplicate, warn the sucker.}    BEGIN        connection := false;        REPEAT {Scan through all lines until a period is encountered.}            tokencount := 0;            REPEAT {Scan through the line until something is found.}                w1 := nextword(stopchar);                IF w1[1] <> ' ' THEN {We've found a real word. This just prevents a blankword from crashing.}                    BEGIN                        addword(w1, idea, wordnum);                        tokencount := tokencount + 1;                        IF tokencount <= wordspertoken THEN                            t1[tokencount] := wordnum                        ELSE                            BEGIN                                error('Reached maximum words per token. Extra ignored.');                                skiptoend(stopchar)                            END                    END            UNTIL (stopchar = ';') OR (stopchar = ':') OR (stopchar = '.') OR eof(inputfile);            IF tokencount > 0 THEN {There is something here to do.}                BEGIN                    WHILE tokencount < wordspertoken DO {Clean up the rest of the token.}                        BEGIN                            tokencount := tokencount + 1;                            t1[tokencount] := 0                        END;                    symetric := 0;                    IF (stopchar = ':') AND NOT idea THEN                        BEGIN {Decide what type of connector.}                            w1 := nextword(stopchar);                            IF checkword(w1, placeholder) THEN        {A recognized word is found. See if it is the correct one.}                                IF placeholder^.uid = leftnum THEN                                    symetric := 1                                ELSE IF placeholder^.uid = rightnum THEN                                    symetric := 2                                ELSE IF placeholder^.uid = symnum THEN                                    symetric := 0                                ELSE                                    error('Definition of connector must be followed by ''left'',''right'' or ''symetric.')                            ELSE {A real error is found.}                                error('Definition of connector must be followed by ''left'',''right'' or ''symetric.');                        END;    {Store it all away now.}                    addtoken(t1, idea, symetric, connection, tokenid, duplicate);                    IF duplicate THEN                        error('Duplicate token encountered.')                END;            WHILE (stopchar <> ';') AND (stopchar <> '.') AND NOT eof(inputfile) DO                skiptoend(stopchar);        UNTIL (stopchar = '.') OR eof(inputfile);    END;{scanline}    PROCEDURE scancentral;    {Keeps everything rolling along. Begins the scanning and portions it out to everyone.}        VAR            idea : boolean;        {True if we are in an idea segment.}            w1 : word;        {A variable to hold the nextword read.}            stopchar : char;        {This variable marks the end of the line.}            placeholder : tablepoint;        {Something needed to use checkword. placeholder^.uid is the uid of the word}    BEGIN        REPEAT            w1 := nextword(stopchar);            IF checkword(w1, placeholder) THEN {Yes the word is found. Do something.}                IF placeholder^.uid = ideanum THEN {A new idea segment is begun.}                    BEGIN                        idea := true;                        scanline(idea);                    END                ELSE IF placeholder^.uid = connum THEN {A new connector segment is begun.}                    BEGIN                        idea := false;                        scanline(idea);                    END                ELSE IF placeholder^.uid = equnum THEN {A new connection segment is begun.}                    parsem;{Well if it gets to here, then the word is not cool. Ignore it and go on. Keep scanning words}{until a match is found or the end of file is reached.}        UNTIL eof(inputfile);    END;{scancentral}BEGIN    Showtext; {Show the text window. Specific to Lightspeed Pascal for the Mac.}    initialize;    write('Inputfile name:');    readln(inputname);    write('Outputfile name:');    readln(outputname);    reset(inputfile, inputname);                {Open the input-file.}    rewrite(outputfile, outputname);            {Open the output file and set it to the beginning.}    scancentral;    print;    close(inputfile);    close(outputfile)END.
  63.  
  64.  
  65.